CS61C 学习笔记

RISC-V Assembly Language

RISC-V 是一种指令集

image.png

这幅图展现了处理器的基本架构

接下来介绍一下 RISC-V 的指令,

加法命令

add x1, x2, x3

减法运算

sub x3, x4, x5

如果有算式

d = e - f

其中 d 是 x3,e 是 x4,f 是 x5

如果我现有 C 语言算式 f = (g + h) - (i + j)

把它翻译成 RISC-V 就是

add x5, x20, x21 # a_tmp = g + h
add x6, x22, x23 # b_tmp = i + j
sub x19, x5, x6 # f = (g + h) - (i + j)

立即加法指令

addi x3, x4, 10

f = g + 10

是一样的,其中 x3 是 f,x4 是 g

一般,我们如果要复制一个寄存器的值,要用指令

add x3, x4, x0

因为 x0 恒为 0

image.png

Load from memory 就是数据从内存中加载进寄存器中

Store to memory 就是数据从寄存器放回内存中

数据通常小于 32 位,但很少小于 8 位

所以,我们把 8 位一组称为一个字节

地址实际上是按照字节计算的例如,32 位就占 4 个字节

小端序约定表示低的地址位对应于低的字节位

image.png

回到 RISC-V 指令

现有 C 语言代码

int A[100]
g = h + A[3]

使用 RISC-V 写就是

lw x10, 12(x15) # x10 = A[3]
add x11, x12, x10
int A[100]
A[10] = h + A[3]

使用 RISC-V 去书写就是

lw x10, 12(x15)
add x10, x12, x10
sw x10, 40(x15)

除了加载 4 个字节的 swlw 以外,我们有可以加载 1 个字节的 sblw

在 RISC-V 中,if 语句的指令是

beq reg1, reg2,L1

如果寄存器 reg1 中的值等于寄存器 reg2 中的值,则跳转到标记为 L1 到语句,否则,进入下一条语句

beq 到意思是 branch if equal

除了

beq 之外还有一些条件控制语句

还有一个无条件分支,总是跳转

看一个例子

f->x10 g->x11 h->x12 i->x13 j->x14
if (i == j)
    f = g + h
else
    f = g - h

翻译成汇编码就是

	bne x13, x14, Else
	add x10, x11, x12
	j Exit
Else: sub x10, x11, x12
Exit:

C 语言中有三种循环类型,while,for 和 do while

每种形式可以重写成另外两种之一,因此,相同的分支方法可以应用于这些所有循环

来看一下 C 语言循环转化到 RISC- V 汇编的例子

image-20250923224342906

RISC-V 中也有按位处理的操作,被称为逻辑操作

image-20250924090255294

这些操作始终有两种变体

在 RISC-V 中没有 not 指令,所以需要用与 11111111 取 xor 操作来代替

移位分为两种,一种是逻辑移位(sll)和立即数形式(slli)

slli x1, x12, 2 # x11 = x12 << 2

将 x12 的值左移 2 位,超出部分丢弃,右侧补零

还有一种是算数移位,算数右移(sra,srai)向右移动 n 位,将最高位符号位填入空出的位置

image-20250924091026682

还有一些有用的 RISC-V 汇编器特性

例如 a0-a7 表示函数调用时的参数寄存器 x10-x17

还有一些伪指令,常见汇编用法的简写语法

mv rd, rs = addi rd, rs, 0
li rd, 13 = addi rd, x0, 13
nop = addi, x0, x0, 0

Function Calls

调用函数有六个基本步骤

  1. 将参数(arguments)放在函数可以访问的位置
  2. 将控制权转移到函数
  3. 获取函数所需的(本地)存储资源
  4. 执行函数的任务
  5. 将返回值放在调用函数可以访问的位置,并恢复函数使用的的寄存器,释放局部存储空间
  6. 将控制权返回到控制点,因为一个函数可以从程序中的多个位置被调用

RSIC-V 函数调用约定

在 RSIC-V 中,所有指令都是 4 个字节,并像数据一样存储在内存中

image-20250924092842359

在调用函数的位置有两步

1008 addi ra, zero, 1016
1012 j sum

这里可以写成一步

1008 jal sum

表示 jump and link 链接并跳转

从函数返回的时候,无条件的跳转到寄存器 ra 的位置

j ra

也可以写成伪指令的形式

ret